﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using ALinq.Mapping.Properties;

namespace ALinq.Mapping
{
    class Error
    {
        internal static FluentMappingException MetaModelNotExists(Type dataContextType)
        {
            return CreateExcetion(() => Strings.MetaModelNotExists, dataContextType.FullName);
        }

        public static FluentMappingException NotExpectedBodyType(string expName, ExpressionType actualType, ExpressionType expectedType)
        {
            return CreateExcetion(() => Strings.NotExpectedBodyType, expName, actualType, expectedType);
        }

        public static FluentMappingException NotExpectedBodyType2(string expName, ExpressionType actualType, ExpressionType expectedType1, ExpressionType expectedType2)
        {
            return CreateExcetion(() => Strings.NotExpectedBodyType, expName, actualType, expectedType1, expectedType2);
        }

        public static ArgumentNullException ArgumentNull(string argumentName)
        {
            return new ArgumentNullException(argumentName);
        }

        private static FluentMappingException CreateExcetion(Expression<Func<string>> msgExpr, params object[] args)
        {
            return new FluentMappingException(msgExpr, args);
        }

        public static FluentMappingException IncorrectMemberMap(string memberName, string tagName)
        {
            return CreateExcetion(() => Strings.IncorrectMemberMap, memberName, tagName);
        }

        public static void ValidateIsMemberExpression(Expression<Func<Expression>> expr)
        {
            var body = (MemberExpression)expr.Body;
            var instance = ((ConstantExpression)body.Expression).Value;
            var member = (FieldInfo)body.Member;

            var value = (LambdaExpression)member.GetValue(instance);
            if (value.Body.NodeType != ExpressionType.MemberAccess)
                throw Error.NotExpectedBodyType(member.Name, value.Body.NodeType, ExpressionType.MemberAccess);
        }

        public static void ValidateArgumentNotNull<T>(Expression<Func<T>> expr) where T : class
        {
            var body = (MemberExpression)expr.Body;
            var instance = ((ConstantExpression)body.Expression).Value;
            var member = (FieldInfo)body.Member;

            var value = (T)member.GetValue(instance);
            if (value == null)
                throw ArgumentNull(member.Name);
        }

        public static void ValidateTypeImplementRequiredClass(Type type, Type baseType)
        {
            if (type.IsSubclassOf(baseType))
                return;

            var exc = new FluentMappingException(() => Strings.TypeNotImplementRequiredClass, type.FullName, baseType.FullName);
            throw exc;
        }

        public static FluentMappingException MemberValueCanNotNull(string memberName)
        {
            var exc = new FluentMappingException(() => Strings.MemberValueCanNotNull, memberName);
            return exc;
        }

        public static FluentMappingException MemberValueCanNotNull<T>(Expression<Func<T>> member)
        {
            var memberName = ((MemberExpression)member.Body).Member.Name;
            var exc = new FluentMappingException(() => Strings.MemberValueCanNotNull, memberName);
            return exc;
        }

        public static FluentMappingException NotContainsItem()
        {
            var exc = new FluentMappingException(() => Strings.NotContainsItem);
            return exc;
        }

        public static FluentMappingException BaseTypeNotMappingType(Type type, Type baseType)
        {
            var exc = new FluentMappingException(() => Strings.BaseTypeNotMappingType, type.FullName, baseType.FullName);
            return exc;
        }

        public static FluentMappingException NotInheritanceType(Type type)
        {
            Debug.Assert(type != null);
            var exc = new FluentMappingException(() => Strings.NotInheritanceType, type.FullName);
            return exc;
        }

        public static FluentMappingException MappingExists(Type type)
        {
            var exc = new FluentMappingException(() => Strings.MappingExists, type.FullName);
            return exc;
        }

        public static FluentMappingException TypeNotImplementRequiredClass(Type type, Type requiredType)
        {
            var exc = new FluentMappingException(() => Strings.TypeNotImplementRequiredClass);
            return exc;
        }

        public static FluentMappingException UnknowModelMappingType(ModelMappingType mappingType)
        {
            var exc = new FluentMappingException(() => Strings.UnknowModelMappingType);
            return exc;
        }

        public static FluentMappingException InvalidProviderType(Type type)
        {
            var exc = new FluentMappingException(() => Strings.InvalidProviderType, type.FullName);
            return exc;
        }

        public static Exception InvalidMember(MemberInfo memberInfo, Type type)
        {
            var exc = new FluentMappingException(() => Strings.InvalidMember, memberInfo.Name, type.FullName);
            return exc;
        }
    }
}
